// test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "..\utc.h"
#include "..\TimeZone.h"
#include "..\DoomsdayDate.h"
#include <fstream>
#include <time.h>

//--------------------------------------------------------------------------------
void print_bias(int tz_from_index, int tz_to_index, const TimeZone::Time& tz_from_time)
{
	TimeZone::TimeZone tz1, tz2;
	if (!TimeZone::TimeZone::getZone(tz_from_index, &tz1))
	{
		wprintf_s(L"Error! First time zone not found\n");
		_ASSERTE(false);
		return;
	}
	if (!TimeZone::TimeZone::getZone(tz_to_index, &tz2))
	{
		wprintf_s(L"Error! Second time zone not found\n");
		_ASSERTE(false);
		return;
	}
	const int bias1 = tz1.biasMinutes(tz_from_time) * 60;
	const int bias2 = tz2.biasSeconds(tz_from_time.utc(bias1));
	wprintf_s(L"%d\n", bias1 - bias2);
}
//--------------------------------------------------------------------------------
bool is_flag(_TCHAR* arg)
{
	return (arg[0] == L'/' || arg[0] == L'-') && arg[1];
}
//--------------------------------------------------------------------------------
void print_help(void)
{
	wprintf_s(L"flags:\n");
	wprintf_s(L"? or help\tprint this help.\n");
	wprintf_s(L"test\t\tperforms full test.\n");
	wprintf_s(L"enum\t\tprints all zones.\n");
	wprintf_s(L"diff\t\tprints difference in seconds between two time zones\n");
	wprintf_s(L"\t\t/diff tz1_index tz2_index date_in_tz1 time_in_tz1\n");
	wprintf_s(L"\t\t/diff 145 35 2008/11/17 11:30:00\n");
	wprintf_s(L"\t\t/diff 145 35\t- will be used current time\n");
	wprintf_s(L"\t\tprints such bias difference that tz2_time = tz1_time + difference.\n");
}
//--------------------------------------------------------------------------------
void test(void)
{
	{
		TimeZone::Utc utc(35);
		int utc1 = utc.fromSecondsFromMidnight(41866);
		int utc2 = utc.fromSecondsFromMidnight(41894);
	}

	wprintf_s(L"Doomsday test... ");
	{
		std::ifstream data("wd_test.txt");
		if (!data.is_open())
		{
			wprintf_s(L"can't open wd_test.txt!\n");
			_ASSERTE(false);
			return;
		}
		while (!data.eof())
		{
			int year(0);
			int month(0);
			int day(0);
			int weekday(0);
			
			data >> year >> month >> day >> weekday;
			if (TimeZone::DoomsdayDate(month, day, year).weekday() != weekday)
			{
				wprintf_s(L"failed!\n");
				_ASSERTE(false);
				return;
			}
		}
		data.close();
	}
	wprintf_s(L"OK\n");

	wprintf_s(L"Sunday test... ");
	{
		std::ifstream data("sd_test.txt");
		if (!data.is_open())
		{
			wprintf_s(L"can't open wd_test.txt!\n");
			_ASSERTE(false);
			return;
		}
		while (!data.eof())
		{
			int year(0);
			int month(0);
			int nth_sunday(0);
			int day(0);
			
			data >> year >> month >> nth_sunday >> day;
			int result = TimeZone::DoomsdayDate(month, day, year).sundayDay(nth_sunday);
			if (result != day)
			{
				wprintf_s(L"failed!\n");
				_ASSERTE(false);
				return;
			}
		}
		data.close();
	}
	wprintf_s(L"OK\n");

	wprintf_s(L"TimeZone test... ");
	{
		std::ifstream data("tz_test.txt");
		if (!data.is_open())
		{
			wprintf_s(L"can't open tz_test.txt!\n");
			_ASSERTE(false);
			return;
		}
		while (!data.eof())
		{
			TimeZone::Time local;
			memset(&local, 0, sizeof(local));

			int tz_index(0);
			int bias(0);

			data >> tz_index >> local.wYear >> local.wMonth >> local.wDay >> local.wHour >> local.wMinute >> local.wSecond >> bias;

			TimeZone::TimeZone timezone;
			bool ret = TimeZone::TimeZone::getZone(tz_index, &timezone);
			if (!ret)
			{
				wprintf_s(L"failed at point 1!\n");
				_ASSERTE(false);
				return;
			}
			if (timezone.biasMinutes(local) != bias)
			{
				wprintf_s(L"failed at point 2!\n");
				_ASSERTE(false);
				return;
			}
			int result = timezone.biasSeconds(local.utc(bias * 60));
			if (result != bias * 60)
			{
				wprintf_s(L"failed at point 3!\n");
				_ASSERTE(false);
				return;
			}

			TimeZone::Time universal;
			timezone.toUniversalTime(local, &universal);
			const int utc = universal.utc(0);
			const int utc2= local.utc(bias * 60);
			if (utc != utc2)
			{
				wprintf_s(L"failed at point 4!\n");
				_ASSERTE(false);
				return;
			}
		}
		data.close();
	}
	wprintf_s(L"OK\n");

	wprintf_s(L"One year test... ");
	{
		TimeZone::TimeZone timezone;
		bool ret = TimeZone::TimeZone::getZone(145, &timezone);
		if (!ret)
		{
			wprintf_s(L"failed at point 1!\n");
			_ASSERTE(false);
			return;
		}

		TimeZone::Time local_year_start;
		local_year_start.wYear = 2008;
		local_year_start.wMonth = 1;
		local_year_start.wDay = 1;

		int seconds_local = local_year_start.utc(0);

		for (int i = 0; i < 365 * 24 * 60; ++i, seconds_local += 60)
		{
			// 1.
			const int utc1 = seconds_local + timezone.biasMinutes(TimeZone::Time(seconds_local)) * 60;
			TimeZone::Time universal1(utc1);
			// 2.
			TimeZone::Time local(seconds_local);
			TimeZone::Time universal2;
			timezone.toUniversalTime(local, &universal2);
			const int utc2 = universal2.utc(0);

			if (utc1 != utc2)
			{
				wprintf_s(L"failed at point 2!\n");
				_ASSERTE(false);
				return;
			}
		}
	}
	wprintf_s(L"OK\n");
}
//--------------------------------------------------------------------------------
int _tmain(int argc, wchar_t* argv[])
{
	if (argc > 1)
	{
		if (is_flag(argv[1]))
		{
			if (!wcscmp(argv[1] + 1, L"?") || !wcscmp(argv[1] + 1, L"help"))
			{
				print_help();
			}
			else if (!wcscmp(argv[1] + 1, L"enum"))
			{
				TimeZone::TimeZone::enumZones();
			}
			else if (!wcscmp(argv[1] + 1, L"test"))
			{
				test();
			}
			else if (!wcscmp(argv[1] + 1, L"diff"))
			{
				if (argc < 3)
				{
					print_help();
				}
				else
				{
					const int tz1 = _wtoi(argv[2]);
					const int tz2 = _wtoi(argv[3]);
					TimeZone::Time time_;
					if (argc < 5)
					{
						time_ = TimeZone::Time(static_cast<int>(time(0)));
					}
					else
					{
						swscanf_s(argv[4], L"%d/%d/%d", &time_.wYear, &time_.wMonth, &time_.wDay);
						swscanf_s(argv[5], L"%d:%d:%d", &time_.wHour, &time_.wMinute, &time_.wSecond);
					}

					print_bias(tz1, tz2, time_);
				}
			}
		}
		else
		{
			print_help();
		}
	}
	else
	{
		print_help();
	}

	return 0;
}

